home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_Binary / DocView.m < prev    next >
Encoding:
Text File  |  1992-12-19  |  10.6 KB  |  425 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    DocView.m
  35.  *
  36.  *    This class handles the scaling of the drawing view. It repositions
  37.  *    The drawing view within itself if the drawing view is smaller than the
  38.  *    size of the clip view. The size of the doc view is:
  39.  *    MAX(clip view frame, drawing view frame).
  40.  *
  41.  *    Version:    2.0
  42.  *    Author:    Ken Fromm
  43.  *    History:
  44.  *            03-07-91        Added this comment.
  45.  */
  46.  
  47. #import "DocView.h"
  48.  
  49. #import <appkit/NXCursor.h>
  50. #import <appkit/NXImage.h>
  51. #import <appkit/Matrix.h>
  52. #import <appkit/ScrollView.h>
  53. #import <dpsclient/wraps.h>
  54. #import <appkit/nextstd.h>
  55.  
  56. @implementation DocView
  57.  
  58. /*
  59. *    Since there is only one subview its easier to keep track of it as an
  60. *    instance variable rather than in the subview list.  Returns any the
  61. *    previous drawing view.
  62. */
  63. - addDrawView:subView
  64. {
  65.     id        oldView;
  66.  
  67.     oldView = drawviewId;
  68.     [oldView  removeFromSuperview];
  69.  
  70.     [self  addSubview:subView];
  71.     drawviewId = subView;
  72.     
  73.     return oldView;
  74. }
  75.  
  76. - setZoomControl:anObject
  77. {
  78.     zoomControl = anObject;
  79.     
  80.     return self;
  81. }
  82.  
  83. - zoomControl
  84. {
  85.     return zoomControl;
  86. }
  87.  
  88. - setHitSetting:(float) value
  89. {    
  90.     hitsetting = value;
  91.  
  92.     return self;    
  93. }
  94.  
  95. /*
  96. *    Scale the hit setting. Using an unscaled hit setting would be like
  97. *    using a boxing glove on a 400% scale.
  98. */
  99. - (float) hitSetting
  100. {    
  101.     return hitsetting * (1.0/scale);
  102. }
  103.  
  104. - setScale:(float)value
  105. {
  106.     scale = value;
  107.     
  108.     return self;
  109. }
  110.  
  111. - (float) scale
  112. {
  113.     return  scale;
  114. }
  115.  
  116. - (BOOL) isZooming
  117. {
  118.     return zooming;
  119. }
  120.  
  121. /*
  122. *    Check whether the frame of the drawingview is in the rectangle passed in.
  123. *    If drop is true, then include the linewidth and the drop shadow as part of the
  124. *    drawingview frame.
  125. */
  126. - getDrawViewInRect:(const NXRect *) aRect  withDrop:(BOOL) drop
  127. {
  128.     id        aView = NULL;
  129.  
  130.     NXRect    viewRect, dropRect;
  131.     
  132.     [drawviewId  getFrame:&viewRect];
  133.     if (drop)
  134.     {    
  135.         dropRect = viewRect;
  136.         NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  137.         NXOffsetRect(&viewRect, rint(LINEWIDTH/2 * scale), rint(LINEWIDTH/2 * scale));
  138.         NXUnionRect(&dropRect, &viewRect);
  139.     }
  140.     if (NXIntersectsRect(aRect, &viewRect))
  141.         aView = drawviewId;
  142.  
  143.     return  aView;
  144. }
  145.  
  146. /*
  147. *    This method is overridden from the View class. When the
  148. *    user is zooming the cursor rect for the zoom cursor is set
  149. *    the the frame of the drawing view.
  150. */
  151. - resetCursorRects
  152. {
  153.     id            imageId, visView;
  154.  
  155.     NXPoint        hotspot;
  156.  
  157.     NXRect        cursorRect, visRect;
  158.  
  159.     if (zooming)
  160.     {
  161.         if (!zoomCursor)
  162.         {
  163.             hotspot.x = hotspot.y = 8.0;
  164.             imageId = [NXImage  newFromSection:"zoom.tiff"];
  165.             zoomCursor = [NXCursor  newFromImage:imageId];
  166.             [zoomCursor setHotSpot:&hotspot];
  167.         }
  168.  
  169.         [self getVisibleRect:&visRect];
  170.         visView = [self getDrawViewInRect:&visRect  withDrop:NO];
  171.         if (visView)
  172.         {
  173.             [visView getFrame:&cursorRect];
  174.             NXIntersectionRect(&visRect, &cursorRect);
  175.             [self addCursorRect:&cursorRect  cursor:zoomCursor];
  176.         }        
  177.         else
  178.             zooming = NO;
  179.     }
  180.  
  181.     return self;
  182. }
  183.  
  184. /*
  185. *    Messaged from the zoom matrix. Starts the zoom loop. At the next
  186. *    mouse down in the drawing view, the scaleDrawView:toPoint: method
  187. *    will be called.
  188. */
  189. - zoom:sender
  190. {
  191.     zooming = YES;
  192.     [self  setZoomControl:sender];
  193.     [self  resetCursorRects];
  194.  
  195.     [window makeKeyAndOrderFront:self];
  196.  
  197.     return self;
  198. }
  199.  
  200. /*
  201. *    Sizes the drawing view from the old scale to the newscale.
  202. *    The frame of the view is used instead of the bounds because
  203. *    the bound will always be the same whereas the frame will
  204. *    provide the size in default coordinates.
  205. */
  206. - sizeView:viewId withScale:(float) newscale
  207. {
  208.     float            scalefactor, sizewidth, sizeheight;
  209.  
  210.     NXRect        viewFrame;
  211.     
  212.     [viewId  getFrame:&viewFrame];
  213.     scalefactor = newscale/scale;
  214.     sizewidth = viewFrame.size.width*scalefactor;
  215.     sizeheight = viewFrame.size.height*scalefactor;
  216.     [viewId sizeTo:rint(sizewidth) :rint(sizeheight)];
  217.  
  218.     return self;
  219. }
  220.  
  221. /* 
  222. *    Scales the drawing view from the old scale to the new scale.
  223. *    The scale method is relative so we use the ratio
  224. *    of the old scale to the new scale to obtain the scaling factor.
  225. */
  226. - scaleView:viewId  withScale:(float) newscale
  227. {
  228.     float     scalefactor;
  229.  
  230.     scalefactor = newscale/scale;
  231.     [viewId scale:scalefactor  :scalefactor];
  232.  
  233.     return self;
  234. }
  235.  
  236. /*
  237. *    Place the view passed in in the center of the doc view
  238. *    if it is smaller than the size of the ClipView. Two passes are made
  239. *    through the loop because adding or removing a horizontal or
  240. *    vertical scrollbar will affect the size of the remaining dimension .
  241. */
  242. - placeView:viewId
  243. {
  244.     BOOL        vert = NO, horiz = NO, done = NO;
  245.  
  246.     int            passes = 0, border_type;
  247.  
  248.     float            margin;
  249.     
  250.     NXSize        contSize, newSize, insetSize, delta;
  251.  
  252.     NXRect         viewFrame, scrollFrame;
  253.  
  254.     margin = 4 * OFFSET * scale;
  255.  
  256.     [viewId  getFrame:&viewFrame];
  257.     [[superview superview]  getFrame:&scrollFrame];
  258.     border_type = [[superview superview]  borderType];
  259.  
  260.     while (!done && ++passes <= 2)
  261.     {
  262.         [ScrollView getContentSize:&contSize forFrameSize:&scrollFrame.size
  263.             horizScroller:horiz  vertScroller:vert borderType:border_type];
  264.  
  265.         newSize.width = MAX(viewFrame.size.width, contSize.width);
  266.         newSize.height = MAX(viewFrame.size.height, contSize.height);
  267.  
  268.         delta.width = newSize.width - viewFrame.size.width;
  269.         delta.height = newSize.height - viewFrame.size.height;
  270.         if (delta.width != 0.0 || delta.height != 0.0)
  271.         {
  272.             if (delta.width < margin)
  273.                 newSize.width += margin - delta.width;
  274.             if (delta.height < margin)
  275.                 newSize.height += margin - delta.height;
  276.         }
  277.  
  278.         horiz = (newSize.width != contSize.width);
  279.         vert = (newSize.height != contSize.height);
  280.         if ((horiz && vert) || (!horiz && !vert))
  281.             done = YES;
  282.         else
  283.             done = NO;
  284.     }
  285.     
  286.     [self  sizeTo:newSize.width  :newSize.height];
  287.  
  288.     insetSize.width = floor((newSize.width - viewFrame.size.width)/2);
  289.     insetSize.height =  floor((newSize.height - viewFrame.size.height)/2);
  290.     [viewId  moveTo:insetSize.width  :insetSize.height];
  291.     if (insetSize.width != 0 || insetSize.height != 0)
  292.         [viewId  setClipping:YES];
  293.     else
  294.         [viewId setClipping:NO];
  295.  
  296.     if (horiz)
  297.         [[superview superview] setHorizScrollerRequired:YES];
  298.     else
  299.         [[superview superview] setHorizScrollerRequired:NO];
  300.     
  301.     if (vert)
  302.         [[superview superview] setVertScrollerRequired:YES];
  303.     else
  304.         [[superview superview] setVertScrollerRequired:NO];
  305.  
  306.     return self;
  307. }
  308.  
  309. /*
  310. *    Scales the view to the tag of the selected matrix cell and then
  311. *    scrolls to the point. The point is in window coordinates so
  312. *    it must be converted to the drawing view  coordinates in order
  313. *    to position it in the same relative place in the view.
  314. */
  315. - scaleDrawView:hitView  toPoint:(NXPoint *) p;
  316. {
  317.     float            newscale;
  318.  
  319.     NXPoint        viewPt;
  320.  
  321.     [window invalidateCursorRectsForView:self];
  322.     newscale = [zoomControl  selectedTag] * 0.01;
  323.     if (hitView && newscale != scale)
  324.     {
  325.         viewPt = *p;
  326.         [self convertPoint:&viewPt fromView:nil];
  327.         [self convertPoint:&viewPt  toView:hitView];
  328.         [window disableDisplay];
  329.             /* Size and then scale the drawing view. The frame of the */
  330.             /* drawing view must reflect the changed size. Scaling */
  331.             /* alone will not change the frame. */
  332.             [self  sizeView:hitView  withScale:newscale];
  333.             [self  scaleView:hitView  withScale:newscale];
  334.             [self  setScale:newscale];
  335.     
  336.             [self  placeView:hitView];
  337.             [self  scrollPoint:&viewPt  inView:hitView  to:p];
  338.         [window reenableDisplay];
  339.         [[window contentView]  display];
  340.     }
  341.     zooming = NO;
  342.  
  343.     return self;
  344. }
  345.  
  346.  
  347. /*
  348.  *    Use the point location relative to the window versus the point relative
  349.  *    to the drawing view (before the scale) to determine where to scroll
  350.  *    the drawing view. We want the same location in the drawing view to
  351.  *    appear where the mouse downed occurred.  The window coordinates
  352.  *    are used and then adjusted by the position of the scrolling frame
  353.  *    because the presence or absence of scrollbars throws the use
  354.  *    of the doc views coordinates awry.
  355.  */    
  356. - scrollPoint:(const NXPoint *) aPt  inView:hitView  to:(const NXPoint *) windowPt
  357. {
  358.     NXPoint        viewPt;
  359.  
  360.     NXSize        contSize;
  361.  
  362.     NXRect         viewFrame, visRect, scrollFrame;
  363.  
  364.     [[superview superview]  getContentSize:&contSize];
  365.     [hitView  getFrame:&viewFrame];
  366.  
  367.     if (viewFrame.size.width > contSize.width || viewFrame.size.height > contSize.height)
  368.     {
  369.         viewPt = *aPt;
  370.         [self  convertPoint:&viewPt  fromView:hitView];        
  371.         [self getVisibleRect:&visRect];
  372.         [[superview superview] getFrame:&scrollFrame];
  373.  
  374.         if (viewFrame.size.width > contSize.width)
  375.             viewPt.x  -= windowPt->x - (scrollFrame.origin.x +scrollFrame.size.width -
  376.                             visRect.size.width);
  377.  
  378.         if (viewFrame.size.height > contSize.height)
  379.             viewPt.y  -= windowPt->y - (scrollFrame.origin.y + scrollFrame.size.height -
  380.                             visRect.size.height);
  381.  
  382.         [self  scrollPoint:&viewPt];        
  383.     }
  384.  
  385.     return self;
  386. }
  387.  
  388. /*
  389.  * This drawSelf method draws a border around the drawing view as well as a
  390.  * drop shadow.  This is only done if it will be visible however. We tell if it is visible
  391.  * if the rectangle passed in is not contained entirely within drawingView frame.
  392. */
  393. - drawSelf:(NXRect *)r :(int) count
  394. {
  395.     id            visView;
  396.  
  397.     NXRect        drawRect, dropRect;
  398.  
  399.     visView = [self getDrawViewInRect:r  withDrop:YES];
  400.     if (visView)
  401.     {
  402.         [visView  getFrame:&drawRect];
  403.         if (!NXContainsRect(&drawRect, r))
  404.         {
  405.             dropRect = drawRect;
  406.             NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  407.  
  408.             PSgsave();
  409.             PSsetgray(NX_BLACK);
  410.             PSsetlinewidth(LINEWIDTH * scale);
  411.             PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height);
  412.             PSrectfill(dropRect.origin.x, dropRect.origin.y,
  413.                 dropRect.size.width, dropRect.size.height);
  414.             PSrectstroke(drawRect.origin.x, drawRect.origin.y,
  415.                 drawRect.size.width, drawRect.size.height);
  416.             PSgrestore();
  417.         }
  418.     }
  419.  
  420.     return self;            
  421. }
  422.  
  423. @end
  424.  
  425.